----------------------------------------------------------------------------


Multiple 'OnMapSingleClick' Command Handler


By General Barron

v1.1 7/14/05


http://ofpec.com/editors/resource_view.php?id=850


----------------------------------------------------------------------------



INTRODUCTION


The 'onmapsingleclick' command is a very powerful and useful scripting command. However, it becomes extremely difficult to work with when you are trying to manage more than one possible command to be run by it.


If you aren't careful, you might 'overwrite' the last command when it is still being used; or you might not disable the command when you want to; or a myriad of other problems might come up. These can be very difficult to work out, and the way around them usually ends up being a messy patchwork of global variables and scripts. After getting fed up of dealing with that problem, I created these scripts.


This lets you cleanly, easily and efficiently 'add' or 'remove' multiple commands from the 'onmapsingleclick' command. Click commands can be set to 'remove' themselves automatically after a number of mapclicks, after a certain amount of time passes, or after a certain condition is met. In addition to the normal parameters passed to the 'OnMapSingleClick' command, you can 'attatch' additional data that will be sent to the code run by the click.



SETTING IT UP


NOTE: the handler is already set up by the HS system, after the "@hs_load" statement in the init.sqs.



SCRIPT USAGE


The most important thing when using this system: NEVER OVERWRITE THE 'ONMAPSINGLECLICK' COMMAND! The whole point is that from now on you will 'add' as many commands as you want to that via this handler. Commands can easily be 'removed' as well--meaning the code will no longer be executed on map clicks. By 'command', I mean the codestring that is normally passed to 'onmapsingleclick'; from now on I'll refer to these as "click commands".



TO ADD A NEW CLICK COMMAND TO THE HANDLER:


[{click code}, <time before removing>, <# of clicks>, <{click condition}>, <{end condition}>, <{remove code}>] call GENB_mapclick_add

RETURNS: index of added click command



{click code} - The string of code to be executed on map click. This code has access to the same variables that normal 'onmapsingleclick' codestrings do (_pos, _shift, _alt, _units). In addition, it is passed an array of extra data in the _this parameter (read below to see how to set this data). Also, it is passed the number of clicks it has left before disabling itself in the variable _clicks. Example: { if(_shift) then {grp1 move _pos} }


<time before removing> - optional. Number of seconds before the click command removes itself. Passing 0 means the command will never be removed this way, no matter how many times the map is clicked.


<# of clicks> - optional. After the map is clicked this many times, the click command will remove itself. For example, setting this to 1 means that after clicking the map once, the click command will then be removed. Passing 0 means the command will never be removed this way, no matter how many times the map is clicked. The current number of clicks left before the click command removes itself is passed to the click code in the _clicks variable.


<{click condition}> - optional. If this boolean condition is NOT met, then the click will NOT count towards the # of clicks that will remove the command. This condition will be passed the exact same data that is passed to the {code} above. A condition of {true} means the clicks will always count. Example: { !(_alt && _shift) }


<{end condition}> - optional. Once this boolean condition is met, the click command will remove itself. A condition that is {true} when the function is called means the command will never be removed in this way. Example: {my_var > 4}.


<{remove code}> - optional. Code that will be executed if the command is removed by one of the automatic methods above. Code is passed a number in the _this parameter, meaning the following:

1 - time limit was reached

2 - end condition was met

3 - click limit was reached

Example: { if(_this == 1) then {hint "Mapclick timed out!"} }


(Note that there are many different ways that the click command can be removed. The command will permanently be removed as soon as the first condition that removes it is met.)



TO CHANGE DATA ATTATCHED TO A CLICK COMMAND:


There is an array of data that is 'attatched' to each click command, and is passed to the command in the _this variable of its code (in addition to the _pos, _shift, _alt and _units variables passed in regular 'onmapsingleclick' commands). To set this data, use this function:



[index, data] call GENB_mapclick_setData

RETURNS: nothing


index - The index of the click command. This number is returned by the add function (see above section).


data - The data to attatch to the command (usually an array). Data will be passed to the click command code in the _this variable.



To read the data attatched to the click command (outside of the click command code itself), use this function:


index call GENB_mapclick_getData

RETURNS: the data attatched to the click command



TO MANUALLY REMOVE A CLICK COMMAND:


If you want to manually remove a click command (instead of setting it to automatically remove itself after a certain amount of time, clicks, etc), use this function:


index call GENB_mapclick_remove

RETURNS: Nothing



MP USAGE


The handler should be fully compatable in MP. Make sure that the init.sqs code gets run on all clients. Then just make all function calls on the client that you want to adjust the mapclick commands for. So if you have 3 players (p1, p2, p3), and you want to add a mapclick command to p2's computer, then use the above functions as normal from a script that only runs on p2's computer.


The click command code will be run locally on the client where the command was added. The same goes for the removal code (if any).


If you are going to be doing any MP scripting that would be complex enough to need my handler, then I would HIGHLY recommend that you use the CoC's Network Services 2 scripts if you aren't already. It makes MP scripting 100x easier (specifically, you will be interested in the functions "fNRemoteCall" and "fNSend"). NS2 can be found here:


http://www.thechainofcommand.com/docs/LIBNETWORK/archive/CoC_NS_2_Pack.zip



CONVERTING EXISTING SCRIPTS


Remember, when using this handler: never overwrite the 'onmapsingleclick' command. So does that mean that other scripts that use this command are incompatable with the handler? The answer is no; it is usually easy to take an existing script that uses the 'onmapsingleclick' command, and make it work with this handler--although you will need some understanding of how the script you are converting uses the command.


If the script just sets up the 'onmapsingleclick' command at the start of the mission and never touches it again, then things all you have to do is take the code that looks like this:


OnMapSingleClick { code used by existing script }


And turn it into this:


[ { code used by existing script } ] call GENB_mapclick_add


If the script adjusts the 'onmapsingleclick' command, then sets it back to { } after a delay, then things are just as simple. Change the first occurence of the command like above, but set the <time before removing> parameter. The second occurence of the command (onmapsingleclick {}) should be deleted entirely.


If the script adjusts the 'onmapsingleclick' command, then sets it back to { } from within the click code, then things are still simple. The old code line should look something like this:


OnMapSingleClick { ...do some stuff... ; onmapsingleclick {} }


Just change it into this:


[ { ...do some stuff... }, 0, 1 ] call GENB_mapclick_add


There are many other ways that the onmapsingleclick command could be used, but these are perhaps the most common methods. If it is used in a more complicated manner, then converting the script will require more work--however, I promise that using my handler will almost certainly be much simpler than any workarounds that are currently being used by the script.



EXAMPLE SCRIPT


_idx = [{ {_x setpos _pos} foreach _this }, 0, 0, {true}, {END_CLICK == 1}] call GENB_mapclick_add


[_idx1, player] call GENB_mapclick_setData


~10


_data = _idx call GENB_mapclick_getData

_data = _data + [unit1]

[_idx, _data] call GENB_mapclick_setData


~10


[{END_CLICK = 1}, 0, 1] call GENB_mapclick_add



This is script is total nonsense, but it shows how to use most of the functions. When run, it will let the player click on the map to teleport certain units there. The map can be clicked as many times as desired. At first, only the player will be teleported. After 10 seconds, the player and unit1 will be teleported. After another 10 seconds, a second click command is added. This command will set a variable that ends the first click command (meaning that the player's next teleport will be their last). Note that there is more than one way we could have removed the first click command.


See the example mission for some more examples of use. However, the different ways you can use the handler are completely unlimited and up to you. If you have ever run into a situation where this script would have really helped you, then you will know what to do with it. Otherwise, you most likely won't see it's potential until you run into the problems inherent in the 'onmapsingleclick' command.



--------------------------------------------


I hope you find this script helpful. Enjoy!


-General Barron